package core;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;

import core.util.CommUtils;
import core.util.Const;
import core.util.CoreDataUtil;
import core.util.IoUtils;
import core.util.SqlData;
import core.util.Unit;

/**
 * 加载文件的类
 * 
 * @author qiwx
 *
 */
@SuppressWarnings("unchecked")
public class CoreLoadFilter implements Filter {
	private static Logger log = core.util.Logger.getLogger(CoreLoadFilter.class);

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
			throws IOException, ServletException {
	}

	@Override
	public void init(FilterConfig chain) throws ServletException {
		try {
			log.debug("........loading.......start.....");
			String fullPath = CoreFileter.class.getResource("").getPath();//
			String cofigPath = fullPath.substring(0, fullPath.indexOf("/classes/") + 1) + "/classes/";
			initService(cofigPath);
			getDataSource(cofigPath);
			log.debug("........loading.......end.....");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加载 dao
	 * 
	 * @param basePath
	 * @throws Exception
	 */
	private void initDao(String basePath) throws Exception {
		String baseDaoXml = CommUtils.getPropValByKey("base.dao.file.name", "conf");
		String xmlDoc = getXml(basePath + "/" + baseDaoXml);
		getXmlPath(basePath, xmlDoc, Const.DAO_FIX);
	}

	/**
	 * 加载 service
	 * 
	 * @param basePath
	 * @throws Exception
	 */
	private void initService(String basePath) throws Exception {
		String baseServiceXml = CommUtils.getPropValByKey("base.service.file.name", "conf");
		String xmlDoc = getXml(basePath + "/" + baseServiceXml);
		getXmlPath(basePath, xmlDoc, Const.SERVICE_FIX);
	}

	@SuppressWarnings("unchecked")
	private void getXmlPath(String basePath, String xmlDoc, String flag) throws Exception {
		Document doc = CommUtils.loadXMLStr(xmlDoc);
		Element root = doc.getRootElement();
		List<Element> datas = root.selectNodes(flag);
		for (int i = 0; i < datas.size(); i++) {
			Element e = datas.get(i);
			String path = e.attributeValue("path");
			String realPath = basePath + "/" + path;
			String xml = getXml(realPath);
			if (Const.SERVICE_FIX.equalsIgnoreCase(flag)) {
				getService(xml);
			} else if (Const.DAO_FIX.equalsIgnoreCase(flag)) {
				getDaoes(xml, path);
			}
		}
	}

	/**
	 * 读取path的目录文件下的内容
	 * 
	 * @param path
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	private static String getXml(String xmlpath) throws Exception {
		InputStream is = null;
		String result = "";
		BufferedReader myReader = null;
		try {
			is = new FileInputStream(xmlpath);
			myReader = new BufferedReader(new InputStreamReader(is, "utf8"));
			String line = null;
			while ((line = myReader.readLine()) != null) {
				result += line;
			}
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} finally {
			IoUtils.close(myReader);
			IoUtils.close(is);
		}

		return result;
	}

	/**
	 * 获得打点配置文件
	 * 
	 * @param xmlDoc
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private void getService(String xmlDoc) throws Exception {
		Document doc = CommUtils.loadXMLStr(xmlDoc);
		Element root = doc.getRootElement();
		List<Element> datas = root.selectNodes("service");
		for (int i = 0; i < datas.size(); i++) {
			Element e = datas.get(i);
			String key = e.attributeValue("id");
			String classPath = e.attributeValue("class");
			String iAction = e.attributeValue("action");
			if (CommUtils.isNull(iAction)) {
				throw new Exception(classPath + " had no implement an action ");
			}
			Class classIntance = Class.forName(iAction);
			Method[] methods = classIntance.getDeclaredMethods();// 不包括继承来的
			for (Method method : methods) {
				String methodName = method.getName();
				Unit u = new Unit();
				u.setClassPath(classPath);
				u.setMethod(methodName);
				String sKey = "/" + key + "/" + methodName + ".do";
				if (CoreDataUtil.dataMap.containsKey(sKey)) {
					throw new Exception("the key:" + sKey + " already have exist");
				} else {
					CoreDataUtil.dataMap.put(sKey, u);
				}
			}
			// 加载forward,
			List<Element> forwrdEs = e.selectNodes("forward");
			for (int j = 0; j < forwrdEs.size(); j++) {
				Element forward = forwrdEs.get(j);
				String urlKey = forward.attributeValue("name");
				if (CommUtils.isNull(urlKey)) {
					throw new Exception(classPath + " has a forward is null ");
				}
				String url = forward.attributeValue("url");
				if (CommUtils.isNull(url)) {
					throw new Exception(classPath + " has a url is null ");
				}
				if (CoreDataUtil.dataMap.containsKey(classPath + "." + urlKey)) {
					throw new Exception("the key:" + classPath + "." + urlKey + " already have exist");
				} else {
					CoreDataUtil.dataMap.put(classPath + "." + urlKey, url);
				}
			}
			// 加载redirect
			List<Element> redirectEs = e.selectNodes("redirect");
			for (int k = 0; k < redirectEs.size(); k++) {
				Element redirect = redirectEs.get(k);
				String urlKey = redirect.attributeValue("name");
				if (CommUtils.isNull(urlKey)) {
					throw new Exception(classPath + " has a redirect is null ");
				}
				String url = redirect.attributeValue("url");
				if (CommUtils.isNull(url)) {
					throw new Exception(classPath + " has a url is null ");
				}
				if (CoreDataUtil.dataMap.containsKey(classPath + "." + urlKey)) {
					throw new Exception("the key:" + classPath + "." + urlKey + " already have exist");
				} else {
					CoreDataUtil.dataMap.put(classPath + "." + urlKey, url);
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void getDaoes(String xmlDoc, String fileName) throws Exception {
		Document doc = CommUtils.loadXMLStr(xmlDoc);
		Element root = doc.getRootElement();
		String namespace = root.attributeValue("namespace");
		if (namespace == null || namespace.length() == 0) {
			throw new Exception(fileName + " have no namespace feild");
		}
		List<Element> datas = root.selectNodes("dao");
		for (int i = 0; i < datas.size(); i++) {
			Element e = datas.get(i);
			String key = e.attributeValue("key");
			SqlData sd = (SqlData) CoreDataUtil.dataMap.get(namespace + "." + key);
			if (sd == null) {
				Element sqlEl = (Element) e.selectSingleNode("sql");
				String sql = sqlEl.getText();
				SqlData data = new SqlData();
				data.setSql(sql);
				CoreDataUtil.dataMap.put(namespace + "." + key, data);
			} else {
				throw new Exception("have the same key:" + namespace + "." + key);
			}
		}
	}

	/**
	 * 加载 数据源
	 * 
	 * @param basePath
	 * @throws Exception
	 */
	private void getDataSource(String basePath) throws Exception {
		String dataSourceXml = CommUtils.getPropValByKey("base.datasource.name", "conf");
		String xmlDoc = getXml(basePath + "/" + dataSourceXml);
		getDataSource(basePath, xmlDoc);
	}

	/**
	 * 加载 数据源
	 * 
	 * @param basePath
	 * @throws Exception
	 */
	private void getDataSource(String basePath, String xmlDoc) throws Exception {
		Document doc = CommUtils.loadXMLStr(xmlDoc);
		Element root = doc.getRootElement();
		List<Element> datas = root.selectNodes("source");
		List<String> dataSourceNames = new ArrayList<String>();
		for (int i = 0; i < datas.size(); i++) {
			Element e = datas.get(i);
			String key = e.attributeValue("id");
			String classPath = e.attributeValue("class");
			Class classIntance = Class.forName(classPath);
			List<Element> properties = e.selectNodes("property");
			Object classObject = classIntance.newInstance();
			for (int k = 0; k < properties.size(); k++) {
				Element property = properties.get(k);
				String propertyName = property.attributeValue("name");
				String methodValue = property.getText();
				String methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
				Method method = classIntance.getMethod(methodName, String.class);// 取要执行的方法
				method.invoke(classObject, methodValue);// methodValue是执行方法时传入的参数
			}
			if (CoreDataUtil.dataSourceMap.containsKey(key)) {
				throw new Exception(key + "已经存在");
			}
			CoreDataUtil.dataSourceMap.put(key, classObject);// 加载数据源到缓存中
		}
		// ConsistHashUtil.init( dataSourceNames );//初始化数据源的hashcode值
	}
}
